﻿using CoreWCF;
using SD.IdentitySystem;
using SD.Infrastructure.DTOBase;
using SD.Infrastructure.Membership;
using SlamDunk.MES.AppService.Maps;
using SlamDunk.MES.Domain.Entities.ExecutionContext;
using SlamDunk.MES.Domain.Entities.PlanContxt;
using SlamDunk.MES.Domain.Entities.QualityContext;
using SlamDunk.MES.Domain.IRepositories;
using SlamDunk.MES.Domain.Mediators;
using SlamDunk.MES.IAppService.DTOs.Inputs;
using SlamDunk.MES.IAppService.DTOs.Outputs.ExecutionContext;
using SlamDunk.MES.IAppService.DTOs.Outputs.PlanContext;
using SlamDunk.MES.IAppService.DTOs.Outputs.QualityContext;
using SlamDunk.MES.IAppService.DTOs.Outputs.ResourceContext;
using SlamDunk.MES.IAppService.Interfaces;
using SlamDunk.ValueObjects.Enums;
using System;
using System.Collections.Generic;
using System.Linq;

namespace SlamDunk.MES.AppService.Implements
{
    /// <summary>
    /// 质量管理服务契约实现
    /// </summary>
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, IncludeExceptionDetailInFaults = true)]
    public class QualityContract : IQualityContract
    {
        #region # 字段及构造器

        /// <summary>
        /// 仓储中介者
        /// </summary>
        private readonly RepositoryMediator _repMediator;

        /// <summary>
        /// 单元事务
        /// </summary>
        private readonly IUnitOfWorkMES _unitOfWork;

        /// <summary>
        /// 依赖注入构造器
        /// </summary>
        public QualityContract(RepositoryMediator repMediator, IUnitOfWorkMES unitOfWork)
        {
            this._repMediator = repMediator;
            this._unitOfWork = unitOfWork;
        }

        #endregion


        //命令部分

        #region # 创建作业计划质量检查 —— void CreateExecutionPlanInspect(string inspectionNo...
        /// <summary>
        /// 创建作业计划质量检查
        /// </summary>
        /// <param name="inspectionNo">质量检查编号</param>
        /// <param name="inspectionName">质量检查名称</param>
        /// <param name="inspectedDate">质检日期</param>
        /// <param name="executionPlanId">作业计划Id</param>
        /// <param name="description">描述</param>
        /// <param name="detailParams">质量检查明细参数模型集</param>
        public void CreateExecutionPlanInspect(string inspectionNo, string inspectionName, DateTime inspectedDate, Guid executionPlanId, string description, IEnumerable<QualityInspectionDetailParam> detailParams)
        {
            #region # 验证

            detailParams = detailParams?.ToArray() ?? Array.Empty<QualityInspectionDetailParam>();
            if (!detailParams.Any())
            {
                throw new ArgumentNullException(nameof(detailParams), "质量检查明细不可为空！");
            }

            #endregion

            IEnumerable<QualityInspectionDetail> details =
                from detailParam in detailParams
                select new QualityInspectionDetail(detailParam.productId, detailParam.productionQuantity, detailParam.qualifiedQuantity, detailParam.sampleQuantity, detailParam.manhour, detailParam.machinehour, detailParam.sort, detailParam.description);

            ExecutionPlanInspection inspection = new ExecutionPlanInspection(inspectionNo, inspectionName, inspectedDate, executionPlanId, description);
            inspection.SetDetails(details);

            this._unitOfWork.RegisterAdd(inspection);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 创建工单质量检查 —— void CreateWorkOrderInspect(string inspectionNo...
        /// <summary>
        /// 创建工单质量检查
        /// </summary>
        /// <param name="inspectionNo">质量检查编号</param>
        /// <param name="inspectionName">质量检查名称</param>
        /// <param name="inspectedDate">质检日期</param>
        /// <param name="workOrderId">工单Id</param>
        /// <param name="description">描述</param>
        /// <param name="detailParams">质量检查明细参数模型集</param>
        public void CreateWorkOrderInspect(string inspectionNo, string inspectionName, DateTime inspectedDate, Guid workOrderId, string description, IEnumerable<QualityInspectionDetailParam> detailParams)
        {
            #region # 验证

            detailParams = detailParams?.ToArray() ?? Array.Empty<QualityInspectionDetailParam>();
            if (!detailParams.Any())
            {
                throw new ArgumentNullException(nameof(detailParams), "质量检查明细不可为空！");
            }

            #endregion

            IEnumerable<QualityInspectionDetail> details =
                from detailParam in detailParams
                select new QualityInspectionDetail(detailParam.productId, detailParam.productionQuantity, detailParam.qualifiedQuantity, detailParam.sampleQuantity, detailParam.manhour, detailParam.machinehour, detailParam.sort, detailParam.description);

            WorkOrder workOrder = this._repMediator.WorkOrderRep.Single(workOrderId);
            WorkOrderInspection inspection = new WorkOrderInspection(inspectionNo, inspectionName, inspectedDate, workOrder.ExecutionPlanId, workOrder.Id, description);
            inspection.SetDetails(details);

            this._unitOfWork.RegisterAdd(inspection);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 修改质量检查 —— void UpdateQualityInspection(Guid qualityInspectionId...
        /// <summary>
        /// 修改质量检查
        /// </summary>
        /// <param name="qualityInspectionId">质量检查Id</param>
        /// <param name="inspectionName">质量检查名称</param>
        /// <param name="inspectedDate">质检日期</param>
        /// <param name="description">描述</param>
        /// <param name="detailParams">质量检查明细参数模型集</param>
        public void UpdateQualityInspection(Guid qualityInspectionId, string inspectionName, DateTime inspectedDate, string description, IEnumerable<QualityInspectionDetailParam> detailParams)
        {
            #region # 验证

            detailParams = detailParams?.ToArray() ?? Array.Empty<QualityInspectionDetailParam>();
            if (!detailParams.Any())
            {
                throw new ArgumentNullException(nameof(detailParams), "质量检查明细不可为空！");
            }

            #endregion

            IEnumerable<QualityInspectionDetail> details =
                from detailParam in detailParams
                select new QualityInspectionDetail(detailParam.productId, detailParam.productionQuantity, detailParam.qualifiedQuantity, detailParam.sampleQuantity, detailParam.manhour, detailParam.machinehour, detailParam.sort, detailParam.description);

            QualityInspection inspection = this._unitOfWork.Resolve<QualityInspection>(qualityInspectionId);
            inspection.UpdateInfo(inspectionName, inspectedDate, description);
            inspection.SetDetails(details);

            this._unitOfWork.RegisterSave(inspection);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 删除质量检查 —— void RemoveQualityInspection(Guid qualityInspectionId)
        /// <summary>
        /// 删除质量检查
        /// </summary>
        /// <param name="qualityInspectionId">质量检查Id</param>
        public void RemoveQualityInspection(Guid qualityInspectionId)
        {
            QualityInspection qualityInspection = this._unitOfWork.Resolve<QualityInspection>(qualityInspectionId);

            #region # 验证

            if (qualityInspection.CheckStatus == CheckStatus.Checking)
            {
                throw new InvalidOperationException("审核中的质量检查不可删除！");
            }
            if (qualityInspection.CheckStatus == CheckStatus.Passed)
            {
                throw new InvalidOperationException("审核通过的质量检查不可删除！");
            }

            #endregion

            this._unitOfWork.RegisterRemove(qualityInspection);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 提交审核质量检查 —— void SubmitQualityInspection(Guid qualityInspectionId)
        /// <summary>
        /// 提交审核质量检查
        /// </summary>
        /// <param name="qualityInspectionId">质量检查Id</param>
        public void SubmitQualityInspection(Guid qualityInspectionId)
        {
            //获取当前用户
            LoginInfo loginInfo = MembershipMediator.GetLoginInfo();
            string operatorAccount = loginInfo?.LoginId;
            string operatorName = loginInfo?.RealName;

            QualityInspection qualityInspection = this._unitOfWork.Resolve<QualityInspection>(qualityInspectionId);
            qualityInspection.Submit(operatorAccount, operatorName);

            this._unitOfWork.RegisterSave(qualityInspection);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 批量提交审核质量检查 —— void SubmitQualityInspections(IEnumerable<Guid>...
        /// <summary>
        /// 批量提交审核质量检查
        /// </summary>
        /// <param name="qualityInspectionIds">质量检查Id集</param>
        public void SubmitQualityInspections(IEnumerable<Guid> qualityInspectionIds)
        {
            #region # 验证

            qualityInspectionIds = qualityInspectionIds?.Distinct().ToArray() ?? Array.Empty<Guid>();
            if (!qualityInspectionIds.Any())
            {
                return;
            }

            #endregion

            //获取当前用户
            LoginInfo loginInfo = MembershipMediator.GetLoginInfo();
            string operatorAccount = loginInfo?.LoginId;
            string operatorName = loginInfo?.RealName;

            ICollection<QualityInspection> qualityInspections = this._unitOfWork.ResolveRange<QualityInspection>(qualityInspectionIds);
            foreach (QualityInspection qualityInspection in qualityInspections)
            {
                qualityInspection.Submit(operatorAccount, operatorName);
            }

            this._unitOfWork.RegisterSaveRange(qualityInspections);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 审核质量检查 —— void CheckQualityInspection(Guid qualityInspectionId...
        /// <summary>
        /// 审核质量检查
        /// </summary>
        /// <param name="qualityInspectionId">质量检查Id</param>
        /// <param name="passed">是否通过</param>
        /// <param name="checkedRemark">审核意见</param>
        public void CheckQualityInspection(Guid qualityInspectionId, bool passed, string checkedRemark)
        {
            //获取当前用户
            LoginInfo loginInfo = MembershipMediator.GetLoginInfo();
            string operatorAccount = loginInfo?.LoginId;
            string operatorName = loginInfo?.RealName;

            QualityInspection qualityInspection = this._unitOfWork.Resolve<QualityInspection>(qualityInspectionId);
            qualityInspection.Check(passed, checkedRemark, operatorAccount, operatorName);

            //质检相关作业计划与工单
            if (passed && qualityInspection is ExecutionPlanInspection executionPlanInspection)
            {
                ExecutionPlan executionPlan = this._unitOfWork.Resolve<ExecutionPlan>(executionPlanInspection.ExecutionPlanId);
                executionPlan.Inspect();

                this._unitOfWork.RegisterSave(executionPlan);
            }
            if (passed && qualityInspection is WorkOrderInspection workOrderInspection)
            {
                WorkOrder workOrder = this._unitOfWork.Resolve<WorkOrder>(workOrderInspection.WorkOrderId);
                workOrder.Inspect();

                this._unitOfWork.RegisterSave(workOrder);
            }

            this._unitOfWork.RegisterSave(qualityInspection);
            this._unitOfWork.Commit();
        }
        #endregion


        //查询部分

        #region # 分页获取作业计划质量检查列表 —— PageModel<ExecutionPlanInspectionInfo> GetExecutionPlanInspectionsByPage(...
        /// <summary>
        /// 分页获取作业计划质量检查列表
        /// </summary>
        /// <param name="keywords">关键字</param>
        /// <param name="executionPlanId">作业计划Id</param>
        /// <param name="checkStatus">审核状态</param>
        /// <param name="startTime">开始时间</param>
        /// <param name="endTime">结束时间</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页容量</param>
        /// <returns>作业计划质量检查列表</returns>
        public PageModel<ExecutionPlanInspectionInfo> GetExecutionPlanInspectionsByPage(string keywords, Guid? executionPlanId, CheckStatus? checkStatus, DateTime? startTime, DateTime? endTime, int pageIndex, int pageSize)
        {
            ICollection<ExecutionPlanInspection> inspections = this._repMediator.QualityInspectionRep.FindExecutionPlanInspectionsByPage(keywords, executionPlanId, checkStatus, startTime, endTime, pageIndex, pageSize, out int rowCount, out int pageCount);

            IEnumerable<Guid> executionPlanIds = inspections.Select(x => x.ExecutionPlanId);
            IDictionary<Guid, ExecutionPlanInfo> executionPlanInfos = this._repMediator.ExecutionPlanRep.Find(executionPlanIds).ToDictionary(x => x.Key, x => x.Value.ToDTO(null, null, null, null, null));

            IEnumerable<ExecutionPlanInspectionInfo> inspectionInfos = inspections.Select(x => x.ToDTO(executionPlanInfos));

            return new PageModel<ExecutionPlanInspectionInfo>(inspectionInfos, pageIndex, pageSize, pageCount, rowCount);
        }
        #endregion

        #region # 分页获取工单质量检查列表 —— PageModel<WorkOrderInspectionInfo> GetWorkOrderInspectionsByPage(...
        /// <summary>
        /// 分页获取工单质量检查列表
        /// </summary>
        /// <param name="keywords">关键字</param>
        /// <param name="executionPlanId">作业计划Id</param>
        /// <param name="workOrderId">工单Id</param>
        /// <param name="checkStatus">审核状态</param>
        /// <param name="startTime">开始时间</param>
        /// <param name="endTime">结束时间</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页容量</param>
        /// <returns>工单质量检查列表</returns>
        public PageModel<WorkOrderInspectionInfo> GetWorkOrderInspectionsByPage(string keywords, Guid? executionPlanId, Guid? workOrderId, CheckStatus? checkStatus, DateTime? startTime, DateTime? endTime, int pageIndex, int pageSize)
        {
            ICollection<WorkOrderInspection> inspections = this._repMediator.QualityInspectionRep.FindWorkOrderInspectionsByPage(keywords, executionPlanId, workOrderId, checkStatus, startTime, endTime, pageIndex, pageSize, out int rowCount, out int pageCount);

            IEnumerable<Guid> executionPlanIds = inspections.Select(x => x.ExecutionPlanId);
            IEnumerable<Guid> workOrderIds = inspections.Select(x => x.WorkOrderId);
            IDictionary<Guid, ExecutionPlanInfo> executionPlanInfos = this._repMediator.ExecutionPlanRep.Find(executionPlanIds).ToDictionary(x => x.Key, x => x.Value.ToDTO(null, null, null, null, null));
            IDictionary<Guid, WorkOrderInfo> workOrderInfos = this._repMediator.WorkOrderRep.Find(workOrderIds).ToDictionary(x => x.Key, x => x.Value.ToDTO(null, null, null, null, null));

            IEnumerable<WorkOrderInspectionInfo> inspectionInfos = inspections.Select(x => x.ToDTO(executionPlanInfos, workOrderInfos));

            return new PageModel<WorkOrderInspectionInfo>(inspectionInfos, pageIndex, pageSize, pageCount, rowCount);
        }
        #endregion

        #region # 获取质量检查明细列表 —— IEnumerable<QualityInspectionDetailInfo> GetQualityInspectionDetails(...
        /// <summary>
        /// 获取质量检查明细列表
        /// </summary>
        /// <param name="qualityInspectionId">质量检查Id</param>
        /// <returns>质量检查明细列表</returns>
        public IEnumerable<QualityInspectionDetailInfo> GetQualityInspectionDetails(Guid qualityInspectionId)
        {
            ICollection<QualityInspectionDetail> details =
                this._repMediator.QualityInspectionDetailRep.Find(qualityInspectionId);

            IEnumerable<Guid> productIds = details.Select(x => x.ProductId);
            IDictionary<Guid, MaterialInfo> productInfos = this._repMediator.MaterialRep.Find(productIds).ToDictionary(x => x.Key, x => x.Value.ToDTO(null));

            IEnumerable<QualityInspectionDetailInfo> detailInfos = details.Select(x => x.ToDTO(productInfos));

            return detailInfos;
        }
        #endregion
    }
}
